package cn.snmp.mutual.org.opennms.protocols.snmp;

import java.io.*;

import cn.snmp.mutual.org.opennms.protocols.snmp.asn1.AsnDecodingException;
import cn.snmp.mutual.org.opennms.protocols.snmp.asn1.AsnEncoder;
import cn.snmp.mutual.org.opennms.protocols.snmp.asn1.AsnEncodingException;

public class SnmpObjectId implements SnmpSyntax, Cloneable, Serializable {
    static final long serialVersionUID = 2633631219460364065L;
    private int[] m_data;
    public static final byte ASNTYPE = 6;

    private static int[] convert(final String idstr) {
        int numIds = 0;
        final char[] idArray = idstr.toCharArray();
        if (idArray.length == 0) {
            final int[] tmp = new int[2];
            tmp[0] = (tmp[1] = 0);
            return tmp;
        }
        if (idArray[0] != '.') {
            ++numIds;
        }
        int x = 0;
        while (x < idArray.length) {
            if (idArray[x++] == '.') {
                ++numIds;
            }
        }
        if (numIds == 0) {
            final int[] tmp2 = new int[2];
            tmp2[0] = (tmp2[1] = 0);
            return tmp2;
        }
        final int[] objects = new int[numIds];
        int objectsNdx = 0;
        int idArrayNdx = 0;
        if (idArray[0] == '.') {
            ++idArrayNdx;
        }
        int oid = 0;
        while (idArrayNdx < idArray.length) {
            if (idArray[idArrayNdx] == '.') {
                objects[objectsNdx++] = oid;
                oid = 0;
            } else {
                oid *= 10;
                switch (idArray[idArrayNdx]) {
                    case '1': {
                        ++oid;
                        break;
                    }
                    case '2': {
                        oid += 2;
                        break;
                    }
                    case '3': {
                        oid += 3;
                        break;
                    }
                    case '4': {
                        oid += 4;
                        break;
                    }
                    case '5': {
                        oid += 5;
                        break;
                    }
                    case '6': {
                        oid += 6;
                        break;
                    }
                    case '7': {
                        oid += 7;
                        break;
                    }
                    case '8': {
                        oid += 8;
                        break;
                    }
                    case '9': {
                        oid += 9;
                        break;
                    }
                }
            }
            ++idArrayNdx;
        }
        objects[objectsNdx++] = oid;
        return objects;
    }

    public SnmpObjectId() {
        (this.m_data = new int[2])[0] = (this.m_data[1] = 0);
    }

    public SnmpObjectId(final int[] data) {
        this();
        if (data != null) {
            SnmpUtil.copy(data, 0, this.m_data = new int[data.length], 0, data.length);
        }
    }

    public SnmpObjectId(final SnmpObjectId second) {
        this(second.m_data);
    }

    public SnmpObjectId(final String strOid) {
        this.m_data = convert(strOid);
        if (this.m_data == null) {
            (this.m_data = new int[2])[0] = (this.m_data[1] = 0);
        }
    }

    public int getLength() {
        return this.m_data.length;
    }

    public int[] getIdentifiers() {
        return this.m_data;
    }

    public void setIdentifiers(final int[] data) {
        if (data != null) {
            SnmpUtil.copy(data, 0, this.m_data = new int[data.length], 0, data.length);
        } else {
            (this.m_data = new int[2])[0] = (this.m_data[1] = 0);
        }
    }

    public void setIdentifiers(final String strOid) {
        this.m_data = null;
        if (strOid != null) {
            this.m_data = convert(strOid);
        }
        if (this.m_data == null) {
            (this.m_data = new int[2])[0] = (this.m_data[1] = 0);
        }
    }

    public void append(final int[] ids) {
        if (ids != null && ids.length != 0) {
            final int[] tmp = new int[this.m_data.length + ids.length];
            SnmpUtil.copy(this.m_data, 0, tmp, 0, this.m_data.length);
            SnmpUtil.copy(ids, 0, tmp, this.m_data.length, ids.length);
            this.m_data = tmp;
        }
    }

    public void append(final String strOids) {
        final int[] tmp = convert(strOids);
        this.append(tmp);
    }

    public void append(final SnmpObjectId second) {
        this.append(second.m_data);
    }

    public void prepend(final int[] ids) {
        if (ids != null && ids.length != 0) {
            final int[] tmp = new int[this.m_data.length + ids.length];
            SnmpUtil.copy(ids, 0, tmp, 0, ids.length);
            SnmpUtil.copy(this.m_data, 0, tmp, ids.length, this.m_data.length);
            this.m_data = tmp;
        }
    }

    public void prepend(final String strOids) {
        final int[] tmp = convert(strOids);
        this.prepend(tmp);
    }

    public void prepend(final SnmpObjectId second) {
        this.prepend(second.m_data);
    }

    public int compare(final int[] ids) {
        int aNdx = 0;
        int bNdx = 0;
        int rc = 0;
        while (aNdx < this.m_data.length || bNdx < ids.length) {
            int a = 0;
            if (aNdx < this.m_data.length) {
                a = this.m_data[aNdx++] + 1;
            }
            int b = 0;
            if (bNdx < ids.length) {
                b = ids[bNdx++] + 1;
            }
            rc = a - b;
            if (rc != 0) {
                break;
            }
        }
        return rc;
    }

    public int compare(final int[] ids, int dist) {
        int aNdx = 0;
        int bNdx = 0;
        int rc = 0;
        while ((aNdx < this.m_data.length || bNdx < ids.length) && --dist >= 0) {
            int a = 0;
            if (aNdx < this.m_data.length) {
                a = this.m_data[aNdx++] + 1;
            }
            int b = 0;
            if (bNdx < ids.length) {
                b = ids[bNdx++] + 1;
            }
            rc = a - b;
            if (rc != 0) {
                break;
            }
        }
        return rc;
    }

    public int compare(final SnmpObjectId cmp) {
        return this.compare(cmp.m_data);
    }

    public boolean isRootOf(final SnmpObjectId leaf) {
        return this.compare(leaf.m_data, this.m_data.length) == 0;
    }

    @Override
    public boolean equals(final Object o) {
        if (o instanceof SnmpObjectId) {
            return this.compare(((SnmpObjectId) o).m_data) == 0;
        }
        if (o instanceof String) {
            return this.compare(convert((String) o)) == 0;
        }
        return o instanceof int[] && this.compare((int[]) o) == 0;
    }

    @Override
    public String toString() {
        final StringBuffer buf = new StringBuffer();
        buf.ensureCapacity(this.m_data.length * 3);
        for (int x = 0; x < this.m_data.length; ++x) {
            buf.append('.');
            buf.append(Integer.toString(this.m_data[x]));
        }
        return buf.toString();
    }

    @Override
    public int hashCode() {
        int hash = 0;
        for (int i = 0; i < this.m_data.length; ++i) {
            hash = hash * 31 + this.m_data[i];
        }
        return hash;
    }

    public byte typeId() {
        return 6;
    }

    public int encodeASN(final byte[] buf, final int offset, final AsnEncoder encoder) throws AsnEncodingException {
        return encoder.buildObjectId(buf, offset, this.typeId(), this.m_data);
    }

    public int decodeASN(final byte[] buf, final int offset, final AsnEncoder encoder) throws AsnDecodingException {
        final Object[] rVals = encoder.parseObjectId(buf, offset);
        if ((byte) rVals[1] != this.typeId()) {
            throw new AsnDecodingException("Invalid ASN.1 type");
        }
        this.m_data = (int[]) rVals[2];
        return (int) rVals[0];
    }

    public SnmpSyntax duplicate() {
        return new SnmpObjectId(this);
    }

    public Object clone() {
        return new SnmpObjectId(this);
    }
}
